The code behind the title page map:

# Get the annual mean temperature
temp <- rast(system.file("extdata/bioclim.tif", package = "sdadata"), lyr = 1)

# Reproject
temp <- temp %>% project("EPSG:3035")

rnaturalearth::ne_countries(returnclass = "sf", scale = 50) %>%
    st_transform(3035) %>%
    ggplot() +
    geom_sf(fill = "lightblue") +
    geom_spatraster(data = temp) +
    scale_fill_viridis_c("Degree", na.value = NA) +
    theme_classic() +
    theme(plot.background  = element_rect(fill = "transparent", color = NA),
    panel.background = element_rect(fill = "transparent", color = NA))

So far…

  • We should know:
    • All essential housekeeping tasks (Git, GitHub, etc)
    • A lot more about data.frame, vector and list
    • Basic concepts related to functions in R

Today

  • More on data structure
  • More on functions
  • Environments and Scoping

Vector calculation

Practice 1

  • Create a numeric vector x1 of length 8 with values between 1-10.
  • Create another vector x2 of length 3 with values between 1-10.
  • Run x1 + x2, x1 * x2, and c(x1, x2).
  • Observe what is going on.
[1]  3 10  2  8  6  9  1  7
[1] 6 9 2
[1]  9 19  4 14 15 11  7 16
[1] 18 90  4 48 54 18  6 63
 [1]  3 10  2  8  6  9  1  7  6  9  2

One example

x <- data.frame(name = "Lei", role = "instructor")
typeof(x)
[1] "list"
class(x)
[1] "data.frame"
class(x) <- c("Lei", class(x)) # Very flexible, but sloppy way
# Note: There is formal way
class(x)
[1] "Lei"        "data.frame"
is(x, "data.frame")
[1] TRUE
is(x, "Lei")
[1] TRUE

Factor

  • Create a factor x_f and f:
x_f <- factor(c("John", "Chris", "Rachel"))
f <- factor(c(1:4, 10))
x_f
f

Factor

Practice 2

  • Have a guess what will be printed out?
levels(x_f)
as.integer(x_f)

Practice 2

  • How about f?
levels(f)
as.integer(f)
  • Challenge: what if I want to convert f to integer, but keep the original values?

Functions

Invoking a function is straightforward, just type the function name and give it the necessary parameters.

sum(1, 3)

# Assign the result to an object
a <- sum(c(1:10))

is.vector(a)

# open the help document using ?+function_name
?sum

What is generic function?

Generic function

Can be extended

plot(x = 1:10, y = 2:11)

plot.Lei <- function(obj){
    print(obj$name)
}
plot(x)

methods("plot")

Function components

function_name <- function(arg1, 
                          arg2 = 1:10, 
                          arg3 = ifelse(arg2 == 2, TRUE, FALSE)){
  body
}

Three essential components of a function:

  • formals(), which is a list of arguments. Could be NULL.
  • body(), the code in the function. R function will return the last thing generated by the function body automatically. If you want to return something else, use return(x).
  • environment(), where the function finds the values. It might change based on where the function is defined.

Without name, the function is called anonymous function (quite useful in many cases).

Practice 3

  • Define a function to convert Fahrenheit to Celsius.

\[Celsius = (Fahrenheit - 32) / 1.8\]

  • Exam temperatures in Fahrenheit c(70, 34, 25, 10, 89, 92, 15), when the temperature in Celsius is lower than -10, give a warning “Stay inside.” and print out this temperature in Celsius.
# Define the function
c_to_f <- function(fah = 0){
  
}

# Initialize the temperature vector
fahs <- c(70, 34, 25, 10, 89, 92, 15)

# Loop over the temperature to check
for (fah in fahs){
  
}

The result should be:

[1] "Stay inside."
[1] -12.22222

Practice 3

c_to_f <- function(fah = 0){
  # returns the the temperature in Celsius 
  # when get a value in Fahrenheit
  # Example: c_to_f(25)
  (fah - 32) / 1.8
}
fahs <- c(70, 34, 25, 10, 89, 92, 15)
for (fah in fahs){
  cel <- c_to_f(fah)
  if (cel < -10){
    print('Stay inside.')
    print(cel)
  }
}

Lexical scoping

Let’s guess some results:

# Name masking
x <- 10
f1 <- function() {
  x <- 1
  x <- x + 1
  print(x)
}
f1()
x

# Search level up
x <- 10
f1 <- function() {
  y <- 12
  f2 <- function(){
    z <- 14
    print(x + y + z)
  }
  f2()
}
f1()

# What about this?
x <- 10
f1 <- function(x) {
  print(x)
}
f1()

Environment and namespace

For example

my_number_checker <- function(x) {
    if(x < 5) {
        print("Too low!")
    } else if(x > 5 & x < 10) {
        print("Just right!!! :)")
    } else {
        print("Too high!")
    }
}

library(ls320)

# Remove the function from R_GlobalEnv
rm(my_number_checker)
# Unload ls320
detach("package:ls320", unload = TRUE)

library(ls320)
library(DG320)

Strategies to deal with conflicts

  • Based on the above figure, the most efficient way is to load the package with the function you want to use later.

    • Leave the good thing to the end.
  • We also could specify the package by using package_name::function_name().

  • Other recent packages to deal with conflicts if you are interested in, e.g. import, and conflicted.

  • I, personally, often assign a preferred package function to a new function: select <- dplyr::select (NOTE: no parentheses) to solve a very common conflict.

    • Where is this new function select?

Homework

  • Read Section 1-3 in Unit1-Module3.
  • Sync your class notes of this week to Github
    • I will check them for participation
    • I might give bonus point for impressive ones
  • Make sure you are okay with GitHub (!!)